namespace IBS.Tests

open System
open IBS.Model
open FsUnit
open NUnit.Framework

module MailboxServiceTest =
    // wait for the operations results
    let inline wait() = System.Threading.Thread.Sleep 400
    let inline getValues (v, s, p, n) = !v, !s, !p, !n
    
    let createService (invInd, errorInd) =
        let m, c = ref 0, ref 0 //messages count, operations count
        let upd x = 
            incr c; incr x
            match !m % invInd, !c % errorInd with
            | 0, _ -> "invalid record"
            | _, 0 -> failwith "error"
            | _    -> null  
        
        let (validated, scheduled, processed, notified) as counters = ref 0, ref 0, ref 0, ref 0
        counters, MailboxService<obj>((fun x -> printfn "v"; incr m; upd validated),
                                      (fun x -> printfn "s"; upd scheduled |> ignore),
                                      (fun x -> printfn "p"; upd processed |> ignore),
                                      (fun x err -> printfn "n"; upd notified |> ignore)) 
       
    [<Test>]
    let ``number of operations is equal to 4000 when posting 1000 correct messages``() =
        let counters, service = createService (5000, 5000)
        [1..1000] |> List.iter service.Schedule
        wait()
        getValues counters |> should equal (1000, 1000, 1000, 1000)
        
        
    [<Test>]
    let ``invalid messages don't get scheduled``() =
        let counters, service = createService (2, 5000)
        [1..1000] |> List.iter service.Schedule
        wait()
        getValues counters |> should equal (1000, 500, 500, 1000)
        
    [<Test>]
    let ``failed to validate messages are not scheduled``() =
        let counters, service = createService (10, 1)
        service.Schedule null
        wait()
        getValues counters |> should equal (1, 0, 0, 1)
        
    [<Test>]
    let ``failed to schedule messages are not processed``() =
        let counters, service = createService (10, 2)
        service.Schedule null
        wait()
        getValues counters |> should equal (1, 1, 0, 1)        
        
    
    [<Test>]
    let ``retry if processing fails``() =
        let counters, service = createService (10, 3)
        service.Schedule null
        wait()
        getValues counters  |> should equal (1, 1, 2, 1)
    
        
        
